package com.common.utils.codegenerator;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author: zengliang
 * @Description: mybatis脚本生成器1.0
 * @Date:Created in 17:33 2022/1/4
 * @Modified By:
 */
public class MybatisScriptGenerator {

    private static Pattern linePattern = Pattern.compile("_(\\w)");
    private static Pattern humpPattern = Pattern.compile("[A-Z]");

    /**
     * 生成mybatis xml脚本
     * @param obj
     * @return
     */
    public static void getGennerateXml(Object obj) {
        StringBuffer s = new StringBuffer();
        String xmlHead = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                "        <!DOCTYPE mapper\n" +
                "                PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n" +
                "                \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n" +
                "        <mapper namespace=\"\">";
        s.append(xmlHead + "\n");
        s.append(getGenerateSqlModel(obj)+"\n");
        s.append(getGenerateSqlInsert(obj)+"\n");
        s.append(getGenerateSqlBatchInsert(obj)+"\n");
        s.append(getGenerateSqlUpdate(obj)+"\n");
        s.append(getGenerateSqlSelect(obj)+"\n");
        s.append("</mapper>");
        //生成xml文件
        createXml(s.toString());
    }

    /**
     * 自动生成mybatis model脚本
     * @param o
     * @return
     */
    public static String getGenerateSqlModel(Object o){
        StringBuffer s = new StringBuffer();
        Class<?> clazz = o.getClass();
        Field[] headers = clazz.getDeclaredFields();

        s.append("<resultMap type=\""+clazz.getSimpleName()+"\" id=\""+clazz.getSimpleName()+"\">\n");
        for(int i = 0; i < headers.length; i++){
            if(i > 0 ){
                s.append("<result property=\""+headers[i].getName()+"\" column=\""+ humpToLine(headers[i].getName())+"\"/>\n");
            }
        }
        s.append("</resultMap>");
        return s.toString();
    }

    /**
     * 自动生成mybatis insert脚本
     * @param o
     * @return
     */
    public static String getGenerateSqlInsert(Object o){
        StringBuffer s = new StringBuffer();
        Class<?> clazz = o.getClass();
        Field[] headers = clazz.getDeclaredFields();
        s.append("<insert id=\"save"+clazz.getSimpleName()+"\" parameterType=\""+clazz.getSimpleName()+"\">\n");
        s.append("insert into "+humpToLine(clazz.getSimpleName())+" (\n");
        s.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append("<if test=\""+headers[i].getName()+" != null\">"+humpToLine(headers[i].getName())+",</if>\n");
            }
        }
        s.append("</trim>\n");
        s.append("<trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append("<if test=\""+headers[i].getName()+" != null\">#{i."+headers[i].getName()+"},</if>\n");
            }
        }
        s.append("</trim>\n");
        s.append("</insert>\n");
        return s.toString();
    }

    /**
     * 自动生成mybatis 批量insert脚本
     * @param o
     * @return
     */
    public static String getGenerateSqlBatchInsert(Object o){
        StringBuffer s = new StringBuffer();
        Class<?> clazz = o.getClass();
        Field[] headers = clazz.getDeclaredFields();
        s.append("<insert id=\"saveBatch"+clazz.getSimpleName()+"\" parameterType=\"List\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n");
        s.append("insert into "+humpToLine(clazz.getSimpleName())+" (\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append(humpToLine(headers[i].getName()) + ",\n");
            }
        }
        s = s.deleteCharAt(s.length() - 1);
        s.append(")values\n");
        s.append("<foreach item=\"i\" collection=\"list\" open=\"\" separator=\",\" close=\"\">\n");
        s.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append("#{i."+headers[i].getName()+"},\n");
            }
        }
        s.append("</trim>\n");
        s.append("</foreach>\n");
        s.append("</insert>\n");
        return s.toString();
    }

    /**
     * 自动生成mybatis update脚本
     * @param o
     * @return
     */
    public static String getGenerateSqlUpdate(Object o){
        StringBuffer s = new StringBuffer();
        Class<?> clazz = o.getClass();
        Field[] headers = clazz.getDeclaredFields();
        s.append("<update id=\"update"+clazz.getSimpleName()+"\" parameterType=\""+clazz.getSimpleName()+"\">\n");
        s.append("update "+humpToLine(clazz.getSimpleName())+"\n");
        s.append("<trim prefix=\"SET\" suffixOverrides=\",\">\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append("<if test=\""+headers[i].getName()+" != null\">"+humpToLine(headers[i].getName())+" = #{i."+headers[i].getName()+"},</if>\n");
            }
        }
        s.append("</trim>\n");
        s.append("where id = #{id}");
        return s.toString();
    }

    /**
     * 自动生成mybatis select脚本
     * @param o
     * @return
     */
    public static String getGenerateSqlSelect(Object o){
        StringBuffer s = new StringBuffer();
        Class<?> clazz = o.getClass();
        Field[] headers = clazz.getDeclaredFields();
        s.append("<select id=\""+clazz.getSimpleName()+"\" parameterType=\"Long\" resultMap=\""+clazz.getSimpleName()+"\">\n");
        s.append("select");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append(""+headers[i].getName()+",");
            }
            if(i == headers.length-1){
                s.deleteCharAt(s.length() - 1);
            }
            s.append("\n");
        }
        s.append("from \n");
        s.append(""+clazz.getSimpleName()+" \n");
        s.append(" <where>\n");
        for(int i=0;i<headers.length;i++){
            if(i > 0){
                s.append("<if test=\""+headers[i].getName()+" != null  and "+headers[i].getName()+" != ''\"> and "+humpToLine(headers[i].getName())+" = #{"+headers[i].getName()+"}</if> \n");
            }
        }
        s.append(" </where>\n");
        s.append("</select>\n");
        return s.toString();
    }

    /**
     * 生成xml方法
     */
    public static void createXml(String xml){
        // 生成的文件路径
        try{
            File directory = new File("");//参数为空
            String canonicalPath = directory.getCanonicalPath();
            int lastFirst = canonicalPath.lastIndexOf("\\");
            String path = canonicalPath + "\\" +canonicalPath.substring(lastFirst+1, canonicalPath.length()) + ".xml";
            File file = new File(path);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
            // write 解决中文乱码问题
            OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(xml);
            bw.flush();
            bw.close();
            fw.close();
            System.out.println("生成xml成功路径："+path);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("生成xml失败");
        }
    }

    /**
     * 驼峰转下划线,最后转为大写
     * @param str
     * @return
     */
    public static String humpToLine(String str) {
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString().toUpperCase();
    }

    /**
     * 下划线转驼峰,正常输出
     * @param str
     * @return
     */
    public static String lineToHump(String str) {
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

}


